# -*- coding: utf-8 -*-
######################
#
# 背景建模，运动物体检测
#
######################
 
 
import sys
 
# import the necessary things for OpenCV
import cv2.cv as cv
 
if __name__ == '__main__':
 
    pBkImg = None
    pFrImg = None
 
    pBkMat = None
    pFrMat = None
    pFrameMat = None
 
    nFrmNum = 0
 
    #创建窗口
    cv.NamedWindow("video", 1)
    cv.NamedWindow("background",1)
    cv.NamedWindow("foreground",1)
    #使窗口有序排列

    cv.MoveWindow("video", 30, 0)
    cv.MoveWindow("background", 360, 0)
    cv.MoveWindow("foreground", 690, 0)

    #打开摄像头
    pCapture = cv.CaptureFromCAM(0)
    if not pCapture:
        print("Can not open camera.")
        sys.exit(1)
 
    #打开视频文件
 #   pCapture = cvCaptureFromFile(sys.argv[1]) if not pCapture:
 #   print("Can not open video file.") sys.exit(1)
 
    #逐帧读取视频
    while 1:
 
        pFrame = cv.QueryFrame( pCapture )
        if not pFrame:
            print("Can not open frame.")
            sys.exit(1)
 
        nFrmNum = nFrmNum + 1
 
        print(nFrmNum)
 
        #如果是第一帧，需要申请内存，并初始化
        if nFrmNum == 1:
            #pBkImg = cv.CreateImage(cv.Size(pFrame.width, pFrame.height), IPL_DEPTH_8U,1)
            pBkImg = cv.CreateImage(cv.GetSize(pFrame), cv.IPL_DEPTH_8U, 1)
            #pFrImg = cv.CreateImage(cv.Size(pFrame.width, pFrame.height), IPL_DEPTH_8U,1)
            pFrImg = cv.CreateImage(cv.GetSize(pFrame), cv.IPL_DEPTH_8U, 1)
 
            pBkMat = cv.CreateMat(pFrame.height, pFrame.width, cv.CV_32FC1)
            pFrMat = cv.CreateMat(pFrame.height, pFrame.width, cv.CV_32FC1)
            pFrameMat = cv.CreateMat(pFrame.height, pFrame.width, cv.CV_32FC1)
 
            #转化成单通道图像再处理
            cv.CvtColor(pFrame, pBkImg, cv.CV_BGR2GRAY)
            cv.CvtColor(pFrame, pFrImg, cv.CV_BGR2GRAY)
 
            cv.Convert(pFrImg, pFrameMat)
            cv.Convert(pFrImg, pFrMat)
            cv.Convert(pFrImg, pBkMat)
        else:
 
            cv.CvtColor(pFrame, pFrImg, cv.CV_BGR2GRAY)
            cv.Convert(pFrImg, pFrameMat)
 
            #高斯滤波先，以平滑图像
            cv.Smooth(pFrameMat, pFrameMat, cv.CV_GAUSSIAN, 3, 0, 0)
 
            #当前帧跟背景图相减
            cv.AbsDiff(pFrameMat, pBkMat, pFrMat)
 
            #二值化前景图
            cv.Threshold(pFrMat, pFrImg, 60, 255.0, cv.CV_THRESH_BINARY)
 
            #进行形态学滤波，去掉噪音
            cv.Erode(pFrImg, pFrImg, None, 1)
            cv.Dilate(pFrImg, pFrImg, None, 1)
 
            #更新背景
            cv.RunningAvg(pFrameMat, pBkMat, 0.003, None)
            #将背景转化为图像格式，用以显示
            cv.Convert(pBkMat, pBkImg)
 
            #显示图像
            cv.Flip(pFrame, None, 0)
            cv.Flip(pBkImg, None, 0)
            cv.Flip(pFrImg, None, 0)
            cv.ShowImage("video", pFrame)
            cv.ShowImage("background", pBkImg)
            cv.ShowImage("foreground", pFrImg)
 
            #如果有按键事件，则跳出循环 此等待也为cvShowImage函数提供时间完成显示 等待时间可以根据CPU速度调整
            if cv.WaitKey(2) >= 0 :
                break
 
 
 
 
    #销毁窗口
    cv.DestroyWindow("video")
    cv.DestroyWindow("background")
    cv.DestroyWindow("foreground")
 
    #释放图像和矩阵
    cv.ReleaseImage(pFrImg)
    cv.ReleaseImage(pBkImg)
 
    cv.ReleaseMat(pFrameMat)
    cv.ReleaseMat(pFrMat)
    cv.ReleaseMat(pBkMat)
 
    cv.ReleaseCapture(pCapture)
 
    sys.exit(0)